package com.tanhua.sso.service;

import com.alibaba.dubbo.config.annotation.Reference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.common.mapper.UserMapper;
import com.tanhua.common.pojo.User;
import com.tanhua.dubbo.server.api.HuanXinApi;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Reference(version = "1.0.0")
    private HuanXinApi huanXinApi;

    // 秘钥
    @Value("jwt.secret")
    private String secret;


    public String login(String phone, String verificationCode) {
        //定义redis的key:
        String redisKey = "CHECK_CODE" + phone;

        //定义是否新用户，默认false;
        boolean isNew = false;

        //校验key:
        String code = redisTemplate.opsForValue().get(redisKey);
        if (!StringUtils.equals(verificationCode, code)) {
            //如果不相等：
            return null;
        }

        //如果相等，校验完成后删除key:
        redisTemplate.delete(redisKey);

        //判断是否是新用户：
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", phone);  // 查询条件
        User user = userMapper.selectOne(queryWrapper);

        if (null == user) { //如果查询为空
            //默认创建用户：
            user = new User();
            user.setMobile(phone);
            user.setPassword(DigestUtils.md5Hex("123456"));  //设置默认密码

            //注册：
            log.info("是新用户，正在添加至数据库~~~");
            userMapper.insert(user);
            isNew = true;

            log.info("新用户注册到环信~");
            Boolean aBoolean = huanXinApi.register(user.getId());
            if (!aBoolean) {
                //环信注册失败
                log.error("环信注册失败！userId :" + user.getId());
            }

        }


        //生产token :

        // 定义 荷载,及jwt 的第二部分数据
        Map<String, Object> claims = new HashMap<String, Object>();
        claims.put("id", user.getId());

        // 生成token
        String jwt = Jwts.builder()
                .setClaims(claims)     //payload，存放数据的位置，不能放置敏感数据，如：密码等
                .setExpiration(new DateTime().plusHours(12).toDate())  // 超时时间 ，12小时
                .signWith(SignatureAlgorithm.HS256, secret)   //设置加密方法和加密盐(配置文件注入)
                .compact();

        try {
            //将登录信息发送到mq：
            Map<String, Object> msg = new HashMap<>();
            msg.put("id", user.getId());
            msg.put("date", new Date());
            rocketMQTemplate.convertAndSend("tanhua-sso-login", msg);
        } catch (MessagingException e) {
            e.printStackTrace();
            log.error("消息发送失败！" + e);
        }
        System.out.println(jwt);

        return jwt + "|" + isNew;
    }


    public User queryUserByToken(String token) {
        try {
            //解析token：

            // 通过token解析数据
            Map<String, Object> body = Jwts.parser()    //此前token 存储的是user的id
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
            System.out.println(body);

            /*//查询数据库是否有user:                        //不走数据库查询，可能是不必要。
            User user = userMapper.selectById(id);*/
            //log.info("body:" + body);
            log.info("id：{}", body.get("id"));
            User user = new User();
            user.setId(Long.valueOf(body.get("id").toString()));

            //还需要用用户的手机号：
            //先走redis查询，没有命中则去数据库查询，再缓存到redis(注意手机号的redisKey的时间与token的失效时间一致)
            String redisKey = "TANHUA_USER_PHONE" + user.getId();

            Boolean aBoolean = redisTemplate.hasKey(redisKey);
            if (aBoolean) { //如果有：
                String mobile = redisTemplate.opsForValue().get(redisKey);
                user.setMobile(mobile);
                return user;
            } else {
                //没有redisKey：走数据库查询：
                User user1 = userMapper.selectById(user.getId());
                user.setMobile(user1.getMobile());

                //将mobile写入redis:注意时间：
                long time = Long.valueOf(body.get("exp").toString()) * 1000 - System.currentTimeMillis();   // 这个时间是token还剩下的时间：单位s
                redisTemplate.opsForValue().set(redisKey, user1.getMobile(), time, TimeUnit.MILLISECONDS);
                return user;
            }

        } catch (ExpiredJwtException e) {
            e.printStackTrace();
            log.info("token已经过期！ token = " + token);
        } catch (Exception e) {
            log.error("token不合法！" + e);
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 更新用户手机：
     *
     * @param id
     * @param newPhone
     * @return
     */
    public Boolean updatePhone(Long id, String newPhone) {

        //先查询新手机号是否已经注册，如果已经注册，就不能修改

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", newPhone);
        List<User> users = userMapper.selectList(queryWrapper);

        if (users.size() > 0) {
            //注册了：
            return false;
        }

        //新用户：
        User user = new User();
        user.setMobile(newPhone);
        user.setId(id);
        return this.userMapper.updateById(user) > 0;

    }
}
